import { GameEvent } from "./GameEvent";
import { UpdateRegister } from "./UpdateRegister";

export class PlayerController implements GameCtrler{

    private readonly maxXMoveSpeed: number = 20;
    private readonly accel: number = 5;

    private node: cc.Node;
    private jumpDuration: number = 0;
    private jumpHeight: number = 0;
    private accLeft: boolean = false;
    private accRight: boolean = false;
    private xMoveSpeed: number = 0;
    private isGameStarted: boolean;
    private initPos: cc.Vec3;
    private playerJumpTween: cc.Tween;
    private playerMoveAreaLimit: cc.Vec2;

    public constructor(node: cc.Node, jumpDuration: number, jumpHeight: number, initPos: cc.Vec3, moveAreaLimit: cc.Vec2){
        this.node = node;
        this.jumpDuration = jumpDuration;
        this.jumpHeight = jumpHeight;
        this.initPos = initPos;
        this.playerMoveAreaLimit = moveAreaLimit;
        UpdateRegister.register(this.update.bind(this));
    }

    public prepareGame(): void {
        this.node.position = this.initPos;
        this.playPlayerJumpLoop();
    }

    public startGame(): void{
        this.xMoveSpeed = 0;
        this.accLeft = false;
        this.accRight = false;
        this.isGameStarted = true;
        cc.systemEvent.on(cc.SystemEvent.EventType.KEY_DOWN, this.onPlayerKeyDown, this);
        cc.systemEvent.on(cc.SystemEvent.EventType.KEY_UP, this.onPlayerKeyUp, this);
    }

    public finishGame(): void{
        this.isGameStarted = false;
        this.stopPlayerJumpLoop();
        cc.systemEvent.off(cc.SystemEvent.EventType.KEY_DOWN, this.onPlayerKeyDown, this);
        cc.systemEvent.off(cc.SystemEvent.EventType.KEY_UP, this.onPlayerKeyUp, this);
    }

    public restartGame(): void {
        this.node.setPosition(this.initPos);
        this.playPlayerJumpLoop();
        this.startGame();
    }

    public getPos(): cc.Vec3{
        return this.node.position;
    }

    private update(dt: number): void {
        if(!this.isGameStarted){
            return;
        }

        let moveDetal = 0;
        if(this.accLeft){
            moveDetal = -this.accel;
        }
        else if(this.accRight){
            moveDetal = this.accel;
        }
        this.xMoveSpeed += moveDetal * dt;

        this.xMoveSpeed = this.clamp(this.xMoveSpeed, -this.maxXMoveSpeed, this.maxXMoveSpeed);
        this.node.x += this.xMoveSpeed;

        let isXValid = this.getPos().x >= this.playerMoveAreaLimit.x && this.getPos().x <= this.playerMoveAreaLimit.y;
        if(!isXValid){
            GameEvent.OnFinishGame();
        }
    }

    private clamp(val: number, min: number, max: number): number{
        return Math.min(Math.max(val, min), max)
    }

    private playPlayerJumpLoop(): void {
        var jumpUpAction = this.playerJumpUp();
        var jumpDownAction = this.playerJumpDown();
        var jumpLoopAction = cc.tween(this.node).sequence(jumpUpAction, jumpDownAction);

        this.playerJumpTween = cc.tween(this.node).repeatForever(jumpLoopAction).start();
    }

    private stopPlayerJumpLoop(): void{
        if(this.playerJumpTween == null){
            return;
        }

        this.playerJumpTween.stop();
        this.playerJumpTween = null;
    }

    private playerJumpUp(): cc.Tween<cc.Node> {
        var moveYTween = cc.tween(this.node).by(this.jumpDuration, { y: this.jumpHeight }, { easing: 'sineOut' });
        return moveYTween;
    }

    private playerJumpDown(): cc.Tween<cc.Node> {
        var moveYTween = cc.tween(this.node).by(this.jumpDuration, { y: -this.jumpHeight }, { easing: 'sineIn' });
        return moveYTween;
    }

    private onPlayerKeyDown(event): void {
        switch(event.keyCode)
        {
            case cc.macro.KEY.a:
            {
                this.accLeft = true;
                break;
            }
            case cc.macro.KEY.d:
            {
                this.accRight = true;
                break;
            }
            default:
            {
                console.log('未识别的键位，请检查代码');
                break;
            }
        }
    }

    private onPlayerKeyUp(event): void {
        switch(event.keyCode)
        {
            case cc.macro.KEY.a:
            {
                this.accLeft = false;
                break;
            }
            case cc.macro.KEY.d:
            {
                this.accRight = false;
                break;
            }
            default:
            {
                console.log('未识别的键位，请检查代码');
                break;
            }
        }
    }
}
